package idavollr

import (
	"io"
	"log"
	"mime"
	"mime/quotedprintable"
	"strings"

	"apiote.xyz/p/asgard/himinbjorg"
	"apiote.xyz/p/asgard/jotunheim"

	"github.com/emersion/go-imap"
	"github.com/emersion/go-imap-move"
	"github.com/emersion/go-imap/client"
	"github.com/emersion/go-sasl"
	"github.com/emersion/go-smtp"
)

func SendRepeatedQuarantine(address *imap.Address, lock himinbjorg.Lock) {
	// todo
	log.Printf("sending repeated quarantine to %s from %+v\n", address.Address(), lock)
}

func SendQuarantine(address *imap.Address) {
	// todo
	log.Printf("sending quarantine to %s\n", address.Address())
}

func MoveMsg(c *client.Client, msg *imap.Message, dest string) error {
	log.Printf("moving %v : %s from %s to %s\n", msg.Envelope.Date, msg.Envelope.Subject, msg.Envelope.From[0].Address(), dest)
	moveClient := move.NewClient(c)
	seqSet := new(imap.SeqSet)
	seqSet.AddNum(msg.Uid)
	return moveClient.UidMoveWithFallback(seqSet, dest)
}

func MoveMultiple(c *client.Client, seqSet *imap.SeqSet, dest string) error {
	moveClient := move.NewClient(c)
	if !seqSet.Empty() {
		log.Println("moving multiple to " + dest)
		err := moveClient.UidMoveWithFallback(seqSet, dest)
		return err
	}
	return nil
}

func MoveFromQuarantine(c *client.Client, mbox *imap.MailboxStatus, address, dest string) error {
	log.Printf("moving %s from quarantine to %s\n", address, dest)
	moveClient := move.NewClient(c)
	from := uint32(1)
	to := mbox.Messages
	allMessagesSet := new(imap.SeqSet)
	allMessagesSet.AddRange(from, to)
	var err error = nil

	messages := make(chan *imap.Message, 10)
	done := make(chan error, 1)
	go func() {
		done <- c.Fetch(allMessagesSet, []imap.FetchItem{imap.FetchEnvelope, imap.FetchUid}, messages)
	}()

	moveSet := new(imap.SeqSet)
	for msg := range messages {
		sender := msg.Envelope.From[0]
		if sender.Address() == address {
			moveSet.AddNum(msg.Uid)
		}
	}
	if !moveSet.Empty() {
		err = moveClient.UidMoveWithFallback(moveSet, dest)
	}
	if err := <-done; err != nil {
		return err
	}
	return err
}

func ForwardMessage(config jotunheim.Config, category, messageID, inReplyTo, subject string, body []byte, recipients []string, sender *imap.Address) error {
	// todo reformat, errors, &c.

	msg := "To: " + strings.Join(recipients, ", ") + "\r\n" +
		"From: " + himinbjorg.MakeNameAddress(sender, true) + "\r\n" +
		"Message-ID: " + messageID + "\r\n" +
		"Subject: " + mime.QEncoding.Encode("utf-8", subject) + "\r\n"
	if inReplyTo != "" {
		msg = msg + "In-Reply-To: " + inReplyTo + "\r\n"
	}
	msg += "Reply-To: " + mime.QEncoding.Encode("utf-8", strings.Replace(config.Mimir.RecipientTemplate, "[:]", category, 1)) + "\r\n" +
		"Content-Type: text/plain; charset=utf-8\r\n" +
		"Content-Transfer-Encoding: quoted-printable\r\n" +
		"\r\n"
	msgReader := strings.NewReader(msg)
	auth := sasl.NewPlainClient("", config.Mimir.ImapUsername, config.Mimir.ImapPassword)
	c, err := smtp.DialTLS(config.Mimir.SmtpAddress, nil)
	if err != nil {
		log.Fatal(err)
	}

	if err = c.Auth(auth); err != nil {
		log.Fatal(err)
	}

	if err := c.Mail(config.Mimir.SmtpSender, nil); err != nil {
		log.Fatal(err)
	}
	for _, recipient := range recipients {
		if err := c.Rcpt(recipient, nil); err != nil {
			log.Fatal(err)
		}
	}

	wc, err := c.Data()
	if err != nil {
		log.Fatal(err)
	}
	_, err = io.Copy(wc, msgReader)
	qpWriter := quotedprintable.NewWriter(wc)
	_, err = qpWriter.Write(body)
	_, err = qpWriter.Write([]byte("\r\n"))
	if err != nil {
		log.Fatal(err)
	}
	err = wc.Close()
	if err != nil {
		log.Fatal(err)
	}

	err = c.Quit()
	if err != nil {
		log.Fatal(err)
	}
	return nil
}

func RemoveMessage(c *client.Client, msgUid uint32, mailbox string) error {
	_, err := c.Select(mailbox, false)
	if err != nil {
		return err
	}

	seqset := new(imap.SeqSet)
	seqset.AddNum(msgUid)

	item := imap.FormatFlagsOp(imap.AddFlags, true)
	flags := []interface{}{imap.DeletedFlag}
	return c.UidStore(seqset, item, flags, nil)
}
